import fetch from 'node-fetch'
import fs from 'fs'

export async function download(
  url: string,
  targetPath: string,
  options: {
    signal?: AbortSignal
    onProgress?: (progress: number) => void
  } = {}
) {
  const response = await fetch(encodeURI(url), { signal: options.signal })
  if (!response.ok || !response.body) {
    throw new Error(`[${response.statusText}]`)
  }

  const body = response.body
  return new Promise<void>((resolve, reject) => {
    const stream = fs.createWriteStream(targetPath)
    const len = parseInt(response.headers.get('content-length') as string, 10)
    let cur = 0

    body.on('data', (chunk) => {
      cur += chunk.length
      options.onProgress?.(cur / len)
    })

    body.pipe(stream)

    body.on('end', () => {
      if (len === cur) {
        options.onProgress?.(1)
        resolve()
      } else {
        stream.end()
        fs.unlinkSync(targetPath)
        reject(new Error('网络波动，下载文件不全'))
      }
    })

    stream.on('finish', () => {
      resolve()
    })

    body.on('error', (error) => {
      stream.end()
      fs.unlinkSync(targetPath)
      reject(error)
    })
  })
}
